/*global pi, RefResource */

// 资源管理器模块
// 管理器不使用超时，由需要的子模块自己实现
// 管理器支持资源的中间状态加载，但需要高层代码来管理资源的中间状态释放
// 资源加载方法
// pi.res.load(path, type, callback)
// 参数type为加载类型，如果是复杂处理的图像或纹理，可以通过JSON类型描述，结构必须为{type:type, param:[['hue', a1, a2, v], ['bright', a1, a2, v]]}，其中属性type为图像或纹理，path和type共同决定是否为相同资源
// 参数callback为回调函数，接口为: callback(result), 如果result中有error属性，则表示错误，其中error的值为整数表示错误类型，reason属性描述原因
pi.mod.define('pi.res', function (pi) {
	"use strict";
	// 定义模块
	var createRefRes, handlerCreate, handlerFree, loadNext, loadError, nextCall, module = {},
		table = {},
		nativeTable = {},
		tableCount = 0,

		callTable = {},
		createTable = {},
		releaseTable = {},
		prevTable = {},
		nextTable = {},
		// 创建c层的释放列表
		dvector = pi.dvector.create(8),
		// 获得C层的释放列表的函数指针
		funcPointer = pi.sysmod.symbol(pi.sysmod.open("pi_lib.dll"), "pi_dvector_push");

	// 定义模块上的类型枚举
	// 下载文件，参数必须有uri, 回调的参数为{data}
	module.DOWNLOAD = 'download';
	// 加载文件，回调参数为{handle: 二进制句柄, size: 字节数大小}
	module.FILE = 'file';
	// 解析ArrayBuffer，回调的参数为：ArrayBuffer
	module.BIN = 'bin';
	// 解析string，回调的参数为：string
	module.STR = 'str';
	// 解析json对象，回调的参数为：json对象
	module.JSON = 'json';
	// 解析图像，回调的参数为：{handle: 图像句柄, width: 宽度, height: 高度}
	module.IMG = 'img';
	// 解析纹理，回调的参数为：{handle: 纹理句柄, width: 宽度, height: 高度}
	module.TEX = 'tex';
	// 解析字体，回调参数为字体句柄
	module.FONT = 'font';
	// 解析网格，回调参数为{handle: 网格句柄, type: "mesh"}
	module.MESH = 'mesh';
	// 解析骨骼，回调参数为{handle: 骨骼句柄, type: 'skeleton'}
	module.SKELETON = 'skeleton';

	// 创建本地资源的方法
	createRefRes = function (funcPointer, dvector, object) {
		return new RefResource(funcPointer, dvector, object);
	};
	// 释放handler的方法
	handlerFree = function (handler) {
		var type;
		if (handler.count < 1) {
			type = handler.type;
			if (handler.freeFunc) {
				handler.freeFunc(handler.handle, handler.handleInfo);
			} else {
				releaseTable[type](handler);
			}
			delete handler.res[(handler.typeParam) ? type + handler.typeParam : type];
			tableCount -= 1;
		}
	};

	// 创建handler的方法
	handlerCreate = function (res, type, typeParam, handle, handleInfo, call) {
		var handler = {
			res: res,
			type: type,
			typeParam: typeParam,
			handle: handle,
			count: 0,
			handleInfo: handleInfo,
			call: [call]
		};
		res[(typeParam) ? type + typeParam : type] = handler;
		tableCount += 1;
		callTable[type](handler);
	};

	nextCall = function (call, handler, type, typeParam) {
		if (!type) {
			type = call.type;
			typeParam = call.typeParam;
		}
		handler.count += 1;
		call.prev = handler;
		handlerCreate(handler.res, type, typeParam, handler.handle, handler.handleInfo, call);
	};

	// 管理器加载失败方法
	loadError = function (handler, result) {
		var i, call, arr = handler.call;
		for (i = arr.length - 1; i >= 0; i -= 1) {
			call = arr[i];
			if (call.prev) {
				call.prev.count -= 1;
				handlerFree(call.prev);
			}
			call.callback(result);
		}
		handler.call = [];
		handlerFree(handler);
	};

	// 管理器下一步加载方法
	loadNext = function (handler, handle, handleInfo) {
		var i, call, arr = handler.call;
		handler.handle = handle;
		if (handleInfo) {
			handler.handleInfo = handleInfo;
		}
		for (i = arr.length - 1; i >= 0; i -= 1) {
			call = arr[i];
			if (call.prev) {
				call.prev.count -= 1;
				handlerFree(call.prev);
			}
			if (call.type !== handler.type) {
				nextTable[call.type](call, handler);
			} else {
				call.callback(createTable[handler.type](handler));
			}
		}
		handler.call = [];
		handlerFree(handler);
	};

	// 定义调用数据方法表
	callTable[module.DOWNLOAD] = function (handler) {
		//通知下载
		/*
			pi.downloadHandle.load(handler.res.uri, handler.res.crc32 || 0, function (result) {
				// 如果是网络错误，这不移出uri，等待下次尝试
				if (result.error === undefined) {
					delete handler.res.uri;
					loadNext(handler, 0);
				} else if (result.error !== 400) {
					delete handler.res.uri;
					loadError(handler, result);
				} else {
					loadError(handler, result);
				}
			});
		*/
	};
	callTable[module.FILE] = function (handler) {
		//通知加载
		pi.worker.handle.load(handler.res.path, function (result) {
			if (result.error === undefined) {
				loadNext(handler, result.data, result.size);
			} else {
				loadError(handler, result);
			}
		});
	};
	callTable[module.IMG] = function (handler) {
		pi.worker.handle.loadImg({
			data: handler.handle,
			size: handler.handleInfo,
			param: handler.typeParam
		}, function (result) {
			var p;
			if (result.error === undefined) {
				p = {
					width: result.width,
					height: result.height
				};
				loadNext(handler, result.data, p);
			} else {
				loadError(handler, result);
			}
		});
	};
	callTable[module.TEX] = function (handler) {
		pi.worker.handle.loadTex(handler.handle, function (result) {
			var p;
			if (result.error === undefined) {
				p = {
					width: result.width,
					height: result.height
				};
				loadNext(handler, result.data, p);
			} else {
				loadError(handler, result);
			}
		});
	};
	callTable[module.FONT] = function (handler) {};
	callTable[module.MESH] = function (handler) {
		pi.worker.handle.loadMesh({
			data: handler.handle,
			size: handler.handleInfo
		}, function (result) {
			if (result.error === undefined) {
				loadNext(handler, result);
			} else {
				loadError(handler, result);
			}
		});
	};
	callTable[module.SKELETON] = function (handler) {
		pi.worker.handle.createSkeleton({
			data: handler.handle,
			size: handler.handleInfo
		}, function (result) {
			if (result.error === undefined) {
				loadNext(handler, result);
			} else {
				loadError(handler, result);
			}
		});
	};
	// 定义对象创建方法表
	createTable[module.FILE] = function (handler) {
		// 用指针创建本地资源对象的方法
		handler.count += 1;
		// RefResource
		var res = createRefRes(funcPointer, dvector, handler);
		res.handle = handler.handle;
		res.size = handler.handleInfo;
		return res;
	};
	createTable[module.IMG] = function (handler) {
		// 用指针创建本地资源对象的方法
		handler.count += 1;
		// RefResource
		var res = createRefRes(funcPointer, dvector, handler);
		res.handle = handler.handle;
		res.width = handler.handleInfo.width;
		res.height = handler.handleInfo.height;
		return res;
	};
	createTable[module.TEX] = function (handler) {
		// 用指针创建本地资源对象的方法
		handler.count += 1;
		// RefResource
		var res = createRefRes(funcPointer, dvector, handler);
		res.handle = handler.handle;
		res.width = handler.handleInfo.width;
		res.height = handler.handleInfo.height;
		return res;
	};
	createTable[module.FONT] = function (handler) {};
	createTable[module.MESH] = function (handler) {
		// 用指针创建本地资源对象的方法
		handler.count += 1;
		// RefResource
		var res = createRefRes(funcPointer, dvector, handler);
		res.handle = handler.handle;
		res.type = module.MESH;
		return res;
	};

	createTable[module.SKELETON] = function (handler) {
		// 用指针创建本地资源对象的方法
		handler.count += 1;
		// RefResource
		var res = createRefRes(funcPointer, dvector, handler);
		res.handle = handler.handle;
		res.type = module.SKELETON;
		return res;
	};

	// 定义对象释放方法表
	releaseTable[module.DOWNLOAD] = function (handler) {};
	releaseTable[module.FILE] = function (handler) {
		pi.mem.free(handler.handle);
	};
	releaseTable[module.IMG] = function (handler) {};
	releaseTable[module.TEX] = function (handler) {};
	releaseTable[module.FONT] = function (handler) {};
	releaseTable[module.MESH] = function (handler) {
		pi.render.t3d.destroyMesh(handler.handle);
	};

	releaseTable[module.SKELETON] = function (handler) {
		pi.render.t3d.destroySkeleton(handler.handle);
	};

	// 定义对象加载路径表
	prevTable[module.DOWNLOAD] = false;
	prevTable[module.FILE] = false;
	prevTable[module.BIN] = module.FILE;
	prevTable[module.STR] = module.FILE;
	prevTable[module.JSON] = module.FILE;
	prevTable[module.IMG] = module.FILE;
	prevTable[module.TEX] = module.IMG;
	prevTable[module.FONT] = module.FILE;
	prevTable[module.MESH] = module.FILE;
	prevTable[module.SKELETON] = module.FILE;

	// 定义对象进一步加载的方法表
	nextTable[module.BIN] = function (call, handler) {
		var arr = pi.lang.createArrayBuffer(handler.handleInfo);
		pi.vcall.writeBuffer(handler.handle, arr, pi.vcall.TYPE_BUFFER, 0, 0, handler.handleInfo);
		call.callback(arr);
	};
	nextTable[module.STR] = function (call, handler) {
		var str = pi.vcall.readBuffer(handler.handle, pi.vcall.TYPE_ANSI_STRING, 0, handler.handleInfo);
		call.callback(str);
	};
	nextTable[module.JSON] = function (call, handler) {
		var jsonVal = pi.vcall.readJson(handler.handle, handler.handleInfo);
		call.callback(jsonVal);
	};
	nextTable[module.IMG] = nextCall;
	nextTable[module.TEX] = function (call, handler) {
		if (handler.type === module.FILE) {
			nextCall(call, handler, module.IMG, call.typeParam);
		} else if (handler.type === module.IMG) {
			nextCall(call, handler, module.TEX, call.typeParam);
		}
	};
	nextTable[module.FONT] = nextCall;
	nextTable[module.MESH] = nextCall;
	nextTable[module.SKELETON] = nextCall;

	// 创建本地资源的方法
	module.create = function (handle, handleInfo, freeFunc) {
		var r, handler = {
			res: nativeTable,
			type: handle,
			handle: handle,
			count: 1,
			handleInfo: handleInfo,
			freeFunc: freeFunc
		};
		nativeTable[handle] = handler;
		tableCount += 1;
		r = createRefRes(funcPointer, dvector, handler);
		r.handle = handle;
		r.handleInfo = handleInfo;
		return r;
	};

	// 模块资源加载方法
	module.load = function (path, type, callback) {
		var typeParam, temp, handler, res = table[path];
		if (!res) {
			res = {
				path: path
			};
			table[path] = res;
		}
		// 如果是复杂类型，则转成字符串
		if (type.typeParam) {
			typeParam = JSON.stringify(type.param);
			type = type.type;
		}
		// 如果是未定义的类型则报错
		if (prevTable[type] === undefined) {
			callback({
				error: -13,
				reason: "type not supported"
			});
			return;
		}

		temp = type;
		// 循环查找可用的handler
		while (true) {
			handler = res[(typeParam) ? temp + typeParam : temp];
			if (handler === undefined) {
				temp = prevTable[temp];
				if (!temp) {
					// 判断是否已经下载
					temp = (res.uri) ? module.DOWNLOAD : module.FILE;
					handlerCreate(res, temp, temp, 0, undefined, {
						type: type,
						typeParam: typeParam,
						callback: callback
					});
					return;
				}
			} else if (handler.handle !== 0) {
				if (handler.type !== type) {
					// 如果不是目标句柄，需要从这个handler开始往下进一步加载
					nextTable[type]({
						type: type,
						typeParam: typeParam,
						callback: callback
					}, handler);
					return;
				} else {
					// 如果是目标句柄，则直接创建本地资源对象，并返回
					callback(createTable[handler.type](handler));
					return;
				}
			} else {
				// 如果句柄为0表示正在加载
				handler.call.push({
					type: type,
					typeParam: typeParam,
					callback: callback
				});
				return;
			}
		}
	};

	// 模块多资源加载方法
	module.loads = function (pathTypeArray, callback) {
		pi.async.mapReduce(pathTypeArray, function (pathType, fun) {
			module.load(pathType[0], pathType[1], fun);
		}, callback);
	};

	// 模块获得资源表中句柄的数量
	module.count = function () {
		return tableCount;
	};

	// 模块配置资源表的方法
	module.config = function (t) {
		//tableCount必须为0，才可以设置新的资源表
		if (tableCount < 1) {
			table = t;
		}
	};

	// 模块资源整理方法
	module.collate = function () {
		var obj, buf = pi.dvector.pop(dvector);
		// 获得释放列表中的所有handler
		while (buf) {
			obj = pi.vcall.readBuffer(buf, pi.vcall.TYPE_OBJECT);
			obj.count -= 1;
			handlerFree(obj);
			buf = pi.dvector.pop(dvector);
		}
	};

	pi.lang.setInterval(module.collate, 200);

	return module;
});